/**
 * @file   PacketHeader.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2013-03-10
 * @brief  DataBus Packet Header.
 *
 * Copyright (C) 2013 Djuro Drljaca <djurodrljaca@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DataBus/Common/PacketHeader.h>

DataBus::PacketHeader::PacketHeader()
    : m_source(0),
      m_destination(0),
      m_packetType(PacketType_Error),
      m_packetId(0),
      m_payloadSize(0)
{
}

DataBus::PacketHeader::PacketHeader(const quint8 source,
                                    const quint8 destination,
                                    const PacketType packetType,
                                    const quint8 packetId,
                                    const quint8 payloadSize)
    : m_source(source),
      m_destination(destination),
      m_packetType(packetType),
      m_packetId(packetId),
      m_payloadSize(payloadSize)
{
}

quint8 DataBus::PacketHeader::getSource() const
{
    return m_source;
}

void DataBus::PacketHeader::setSource(const quint8 source)
{
    m_source = source;
}

quint8 DataBus::PacketHeader::getDestination() const
{
    return m_destination;
}

void DataBus::PacketHeader::setDestination(const quint8 destination)
{
    m_destination = destination;
}

DataBus::PacketType DataBus::PacketHeader::getPacketType() const
{
    return m_packetType;
}

void DataBus::PacketHeader::setPacketType(const PacketType packetType)
{
    m_packetType = packetType;
}

quint8 DataBus::PacketHeader::getPacketId() const
{
    return m_packetId;
}

void DataBus::PacketHeader::setPacketId(const quint8 packetId)
{
    m_packetId = packetId;
}

quint8 DataBus::PacketHeader::getPayloadSize() const
{
    return m_payloadSize;
}

void DataBus::PacketHeader::setPayloadSize(const quint8 payloadSize)
{
    m_payloadSize = payloadSize;
}

QByteArray DataBus::PacketHeader::toBinary() const
{
    // Create array
    QByteArray packetData(6, '\0');

    packetData[0] = m_source;
    packetData[1] = m_destination;
    packetData[2] = m_packetType;
    packetData[3] = m_packetId;
    packetData[4] = m_payloadSize;
    packetData[5] = DataBus::calculateChecksum(packetData, 0, 5);

    // Return array
    return packetData;
}

bool DataBus::PacketHeader::parse(const QByteArray &packetHeaderData,
                                  const int startIndex,
                                  PacketHeader *packetHeader)
{
    // Check input parameters
    if ((startIndex < 0) ||
        (startIndex >= packetHeaderData.size()))
    {
        // Error, invalid start index
        return false;
    }

    if ((packetHeaderData.size() - startIndex) < 6)
    {
        // Error, data is not big enough
        return false;
    }

    if (packetHeader == 0)
    {
        // Error, null pointer
        return false;
    }

    // Parse header checksum
    quint8 headerChecksum = (quint8)packetHeaderData.at(startIndex + 5);

    bool ok = false;
    quint8 calculatedChecksum = DataBus::calculateChecksum(packetHeaderData, startIndex, 5, &ok);

    if ((ok == false) ||
        (headerChecksum != calculatedChecksum))
    {
        // Error, invalid checksum
        return false;
    }

    // Parse source
    quint8 source = (quint8)packetHeaderData.at(startIndex + 0);

    // Parse destination
    quint8 destination = (quint8)packetHeaderData.at(startIndex + 1);

    // Parse packet type
    quint8 packetTypeValue = (quint8)packetHeaderData.at(startIndex + 2);

    if (packetTypeValue > PacketType_ExecuteClientMethodResponse)
    {
        // Error, invalid packet type value
        return false;
    }

    PacketType packetType = (PacketType)packetTypeValue;

    // Parse packet ID
    quint8 packetId = (quint8)packetHeaderData.at(startIndex + 3);

    // Parse payload size
    quint8 payloadSize = (quint8)packetHeaderData.at(startIndex + 4);

    // Save values
    packetHeader->setSource(source);
    packetHeader->setDestination(destination);
    packetHeader->setPacketType(packetType);
    packetHeader->setPacketId(packetId);
    packetHeader->setPayloadSize(payloadSize);

    // Success
    return true;
}
